#ifndef __MCS__OBJECT__HPP
#define __MCS__OBJECT__HPP

#include "String.hpp"

class Object
{
private:
	Object(Object const &);
	Object & operator=(Object const &);
protected:
	virtual ~Object()
	{
		instances_[globalIndex_] = instances_.back();
		instances_[globalIndex_]->globalIndex_ = globalIndex_;
		globalIndex_ = -1;
		instances_.pop_back();
	}
public:
	static bool allObjectsRemoved() { return instances_.empty(); }

	Object() 
		: refCounter_(0)
	{
		globalIndex_ = instances_.size();
		instances_.push_back(this);
	}

	void retain()
	{
		++refCounter_;
	}
	
	void release()
	{
		if(!--refCounter_) 
		{
			delete this;
		}
	}
private:
	size_t refCounter_;
	size_t globalIndex_;

	static std::vector<Object*> instances_;
};

namespace detail
{
	template<class T> class trusted_cast_tag;

	class SafeBoolHelper
	{
	public:
		typedef void * (SafeBoolHelper::*XType)(int,bool,void*);
		XType first;
		XType second;
	};

	typedef SafeBoolHelper::XType (SafeBoolHelper::* SaveBool);
}

template<class T> class ptr
{
public:
	ptr()
		: pObj_()
	{}
	
	ptr(T * obj)
		: pObj_(obj)
	{
		if(pObj_)
			pObj_->retain();
	}
	
	template<class Y> ptr(Y * obj)
		: pObj_(obj)
	{
		if(pObj_)
			pObj_->retain(); 
	}

	template<class Y> ptr(detail::trusted_cast_tag<Y*> const & );
	template<class Y> ptr(detail::trusted_cast_tag< ptr<Y> > const & );
	
	ptr(ptr<T> const & other)
		: pObj_(other.get())
	{
		if(pObj_)
			pObj_->retain();
	}

	template<class Y> ptr(ptr<Y> const & other)
		: pObj_(other.get())
	{
		if(pObj_)
			pObj_->retain();
	}

	~ptr()
	{
		if(pObj_)
			pObj_->release();
	}

	ptr<T> & operator=(T * other)
	{
		if(other) other->retain();
		T * tmp = pObj_;
		pObj_ = other;
		if(tmp) tmp->release();
		return *this;
	}

	ptr<T> & operator=(ptr<T> const & other)
	{
		return operator=(other.pObj_);
	}
	
	template<class Y> ptr<T> & operator=(ptr<Y> const & other)
	{
		return operator=(other.get());
	}
	
	T * operator->() const
	{
		return pObj_; 
	}
	
	bool operator!() const
	{
		return !pObj_; 
	}
	
	operator detail::SaveBool() const
	{
		return pObj_ ? &detail::SafeBoolHelper::second : 0;
	}

	template<class Y> ptr<Y> staticCast() const
	{
		return static_cast<Y*>(pObj_);
	}
	
	template<class Y> ptr<Y> dynamicCast() const
	{
		return dynamic_cast<Y*>(pObj_);
	}

	T * get() const
	{
		return pObj_;
	}

	void swap(T * & other)
	{
		T * tmp = pObj_;
		pObj_ = other;
		other = tmp;
	}
	
	void swap(ptr<T> & other)
	{
		swap(other.pObj_);
	}
private:
	T * pObj_;
};

#endif //__MCS__OBJECT__HPP
